package eece261.dChatter;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.MulticastSocket;
import java.net.SocketException;

import android.text.Spannable;
import android.text.style.ForegroundColorSpan;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.TextView.BufferType;

public class dChatListener implements Runnable {

	// For logging.
	private static final String TAG = "JoinGroup";
	
	private dChatMessage    in_msg_;
	private DatagramPacket  packet_;
	//socket used to listen to multicast stream
	private MulticastSocket socket_;
	//used to append new mesages to the screen
	//
	private TextView        text_log_;
	//used to post full scroll after apending to text_log_
	//usure if it works
	private ScrollView      scroll_;
	//Used to determine if any packets are lost
	private dChatRecover    state_recover_;
	//Used to determine current user id
	//Currently UserID = d, when IP = a.b.c.d
	private int				user_number_;
	//Used to determine if you ware waiting on a response to packet request
	private boolean         recovery_wait_;
	//Last message appended to the screen
	private String          Last_MSG_;
	
	//ctor
	public dChatListener(MulticastSocket socket, TextView text_log, ScrollView scroll) {
		Last_MSG_ = null;
		byte[] buffer = new byte[200];
		packet_ = new DatagramPacket(buffer, 200);
		socket_ = socket;
		text_log_ = text_log;
		scroll_ = scroll;
		user_number_ = 0;
	}
	
	//sets UserID
	public void setUserNumber(int num)
	{
		this.user_number_ = num;
	}
	//Returns Last message appended to the screen
	public String getLastMSG()
	{
		if(Last_MSG_ == null)
		{
			return "";
		}
		return this.Last_MSG_;
	}
	//Add message to circle queue used by dChatRecoverer
	//to keep track of last messages received
	public void appendUserMSG(String str)
	{
		state_recover_.appendUserMsg(str);
	}

	public void run() {
	    try {
	    //loop forever
        while (true) {
          //read in new packet from multicast stream
          socket_.receive(packet_);
          //Packet Request Response
          if(packet_.getData()[0] == 2 && recovery_wait_ == true)
          {
        	  in_msg_ = new dChatMessage(packet_);
        	  //detect if packet is one that requested
        	  if(in_msg_.message().equals(state_recover_.getRecoveryStr()))
        	  { 
        		  //IF good packet and have message the person replied to
        		  if(in_msg_.good()&& 
        				  (this.state_recover_.isConsistent(in_msg_.last_message())))
        		  {
        			  recovery_wait_ = false;
        			  String temp = null;
        			  //Empty Recovery stack
        			  while(true)
        			  {
        				  temp = this.state_recover_.retrieveStack();
        				  if(temp == null)
        				  {
        					  break;
        				  }
        				  //Color name based off of UserID in packet
        				  //I know method works, just not sure if it works
        				  //here
        				  Spannable t1 = (Spannable) text_log_.getText();
        				  String LsMessage = temp;
        				  this.Last_MSG_ = temp;
        				  text_log_.setText(LsMessage,BufferType.SPANNABLE);
        	        	  Spannable sText = (Spannable) text_log_.getText();
        	        	  int pos = 0;
        	        	  while(temp.charAt(pos)!=':')
        	        	  {
        	        		  pos++;
        	        	  }
        	        	  int c = in_msg_.getUserCode();
        	        	  //set color
        	        	  sText.setSpan(new ForegroundColorSpan((c << 16) | (c << 8) | c), 1,  pos+3,0);
        	        	  text_log_.setText(t1);
        				  this.text_log_.append(sText);
        				  this.state_recover_.appendUserMsg(temp);
        				  scroll_.post(new Runnable() {
        						public void run() {
        							scroll_.fullScroll(ScrollView.FOCUS_DOWN);
        						}
        				  });
        			  }
        		  }
        		  else
        		  {
        			  //need another packet
            		  state_recover_.setRecoveryStr(in_msg_.last_message());
            		  //put msg on Recovery stack
            		  state_recover_.appendStack(in_msg_.message());
            		  PcktRequest(in_msg_);
        		  }
        		  
        	  }
        	  else
        	  {
        		  //Not your packet
        	  }
          }
          else if(packet_.getData()[0] == 2 && recovery_wait_ == false)
          {
        	  //ignore packet
          }
          else if(packet_.getData()[0] == 1)
          {
        	  //prepare to send out packet that was lost
        	  //if it contains your user_code
        	  dChatMessage t = new dChatMessage(packet_);
        	  dChatMessage d;
        	  //only answer back if your UserID is same as packet request ID
        	  if(t.getUserCode() == this.user_number_)
        	  {
        		  String str = 
        			  state_recover_.getPrevUserMsg(t.message());
        		  if(str == null)
        		  {
        			  d = new dChatMessage(t.message(),2,
        					  t.getInetSockAdr(), user_number_);
        		  }
        		  else
        		  {
        			  d = new dChatMessage(t.message(),str,2,
        					  t.getInetSockAdr(),user_number_);
        		  }
        		  this.packet_ = d.packet();
        		  this.socket_.send(this.packet_);
        	  }
          }
          //Normal Packet
          else if(packet_.getData()[0] == 0)
          {
        	  in_msg_ = new dChatMessage(packet_);
        	  if (in_msg_.good()&& 
        			  state_recover_.isConsistent(in_msg_.last_message()))
        	  {
        		  String temp = in_msg_.message();
				  Spannable t1 = (Spannable) text_log_.getText();
				  String LsMessage = temp;
				  this.Last_MSG_ = temp;
				  text_log_.setText(LsMessage,BufferType.SPANNABLE);
	        	  Spannable sText = (Spannable) text_log_.getText();
	        	  int pos = 0;
	        	  while(temp.charAt(pos)!=':')
	        	  {
	        		  pos++;
	        	  }
	        	  int c = in_msg_.getUserCode();
	        	  sText.setSpan(new ForegroundColorSpan((c << 16) | (c << 8) | c), 1,  pos+3,0);
	        	  text_log_.setText(t1);
				  this.text_log_.append(sText);
				  
        		  state_recover_.appendUserMsg(in_msg_.message());
        		  text_log_.append(in_msg_.message());
        		  scroll_.post(new Runnable() {
        			  public void run() {
        				  scroll_.fullScroll(ScrollView.FOCUS_DOWN);
        			  }
        		  });
        	  }
        	  else
        	  {
        		  state_recover_.setRecoveryStr(in_msg_.last_message());
        		  state_recover_.appendStack(in_msg_.message());
        		  this.PcktRequest(in_msg_);
        	  }
          }
        }
      }
      catch (IOException e) {
      }
	}
	//Create packet request
	//UserID in packet is equal to packet that caused you to enter this method
	private void PcktRequest(dChatMessage inMsg) {
		dChatMessage t = new dChatMessage(inMsg.last_message(), 1, inMsg.getInetSockAdr(), inMsg.getUserCode());
		try {
			this.packet_ = t.packet();
			this.socket_.send(packet_);
		} catch (SocketException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
